package base;

import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.image.BufferStrategy;

import javax.swing.JFrame;

import base.world.IWorldRunnable;

import com.world.WorldMain;

public class Start extends Canvas implements Runnable
{
	private static final long serialVersionUID = 1L;
	
	public static final String WIN_VERSION = "0.0.1";
	
	public static final int WIN_WIDTH = 160;
	public static final int WIN_HEIGHT = WIN_WIDTH/12*9;
	public static final int WIN_SCALE = 3;
	public static final String WIN_TITLE = "Project TNT v" + WIN_VERSION;
	
	public static final int FPS_MAX = 60;
	public static final double UPDATES_PER_TICK = 1000000000D / FPS_MAX;
	
	private static JFrame winFrame;
	private static BufferStrategy winBuffer;
	protected static boolean running = false;
	
	public static IWorldRunnable theWorld;
	public static IWorldRunnable theNextWorld;
	public static boolean theEnd = false;
	
	public Start()
	{
		winFrame = new JFrame("JavaApplication");
		theWorld = new WorldMain();
		theNextWorld = null;
		initWindow(winFrame);
	}
	
	public static void main(String[] args)
	{
		new Start().start();
	}
	
	public synchronized void start()
	{
		running = true;
		
		/**Thread initialization*/
		new Thread(this).start();
	}
	
	public synchronized void terminate()
	{
		running = false;
	}
	
	public void exit()
	{
		theWorld.destroyWorld();
		if (theWorld.canClearWorld())
		{
			theWorld = null;
			this.terminate();
		}
	}
	
	public void run()
	{
		theWorld.initWorld();
		
		double deltaTime = 0;
		long prevTime = System.currentTimeMillis();
		long initTime = System.nanoTime();
		
		while(running)
		{
			long curTime = System.nanoTime();
			deltaTime += (curTime - initTime) / UPDATES_PER_TICK;
			initTime = curTime;
			
			//Set false to cap render updates
			boolean renderAble = true;
			
			//Update cycle
			while(deltaTime >= 1)
			{
				deltaTime--;
				/**MAIN UPDATE - INIT*/
				updateMain();
				/**MAIN UPDATE - END*/
				//Enable render cycle
				renderAble = true;
			}
			
			try
			{
				Thread.sleep(2);
			}
			catch(InterruptedException e) {}
			
			//Render cycle
			if (renderAble)
			{
				/**MAIN RENDER - INIT*/
				renderMain();
				/**MAIN RENDER - END*/
			}
			
			//If >= 1 second
			if (System.currentTimeMillis() - prevTime >= 1000)
			{
				//Reset Timer
				prevTime += 1000;
			}
			
			if (theEnd)
			{
				this.exit();
			}
		}
		
		try
		{
			Thread.sleep(100);
		}
		catch(InterruptedException e) {}
		
		getWindow().dispose();
	}
	
	public void updateMain()
	{
		if (theWorld != null)
		{
			theWorld.update();
		}
		
		/**WORLD TRANSITIONS*/
		if (theNextWorld != null && theWorld.canClearWorld())
		{
			theWorld = theNextWorld;
			theNextWorld = null;
		}
	}
	
	public void renderMain()
	{
		winBuffer = getBufferStrategy();
		if (winBuffer == null)
		{
			//Create BufferStrategy
			createBufferStrategy(2);
			return;
		}
		
		Graphics2D g = (Graphics2D) winBuffer.getDrawGraphics();
		
		//Draw Background
		g.setColor(Color.BLACK);
		g.fillRect(0,0,getWidth(),getHeight());
		
		//Draw Images
		if (theWorld != null)
		{
			theWorld.render(g);
		}
		
		//Clear memory
		g.dispose();
		//Draw buffer strategy
		winBuffer.show();
	}
	
	public void initWindow(JFrame par0Frame)
	{
		//Setup window size
		setMinimumSize(new Dimension(WIN_WIDTH*WIN_SCALE, WIN_HEIGHT*WIN_SCALE));
		setMaximumSize(new Dimension(WIN_WIDTH*WIN_SCALE, WIN_HEIGHT*WIN_SCALE));
		setPreferredSize(new Dimension(WIN_WIDTH*WIN_SCALE, WIN_HEIGHT*WIN_SCALE));
		
		//Setup window
		par0Frame.setTitle(WIN_TITLE);
		par0Frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		par0Frame.setLayout(new BorderLayout());
		
		//Setup window layout
		par0Frame.add(this, BorderLayout.CENTER);
		par0Frame.pack();
		par0Frame.setResizable(false);
		par0Frame.setLocationRelativeTo(null);
		par0Frame.setVisible(true);
	}
	
	public static void setTheEnd()
	{
		theEnd = true;
	}
	
	public static JFrame getWindow()
	{
		return Start.winFrame;
	}
}